import { useRouter } from "next/router"; import z from "zod"; import { AppSettings } from "@calcom/app-store/_components/AppSettings"; import { InstallAppButton } from "@calcom/app-store/components"; import { InstalledAppVariants } from "@calcom/app-store/utils"; import DisconnectIntegration from "@calcom/features/apps/components/DisconnectIntegration"; import { useLocale } from "@calcom/lib/hooks/useLocale"; import { RouterOutputs, trpc } from "@calcom/trpc/react"; import { App } from "@calcom/types/App"; import { AppGetServerSidePropsContext } from "@calcom/types/AppGetServerSideProps"; import { Alert, Button, EmptyScreen, List, AppSkeletonLoader as SkeletonLoader, ShellSubHeading, } from "@calcom/ui"; import { FiBarChart, FiCalendar, FiCreditCard, FiGrid, FiPlus, FiShare2, FiVideo, } from "@calcom/ui/components/icon"; import { QueryCell } from "@lib/QueryCell"; import { CalendarListContainer } from "@components/apps/CalendarListContainer"; import IntegrationListItem from "@components/apps/IntegrationListItem"; import InstalledAppsLayout from "@components/apps/layouts/InstalledAppsLayout"; function ConnectOrDisconnectIntegrationButton(props: { credentialIds: number[]; type: App["type"]; isGlobal?: boolean; installed?: boolean; invalidCredentialIds?: number[]; }) { const { type, credentialIds, isGlobal, installed } = props; const { t } = useLocale(); const [credentialId] = credentialIds; const utils = trpc.useContext(); const handleOpenChange = () => { utils.viewer.integrations.invalidate(); }; if (credentialId) { if (type === "stripe_payment") { return ( ); } return ( ); } if (!installed) { return (
); } /** We don't need to "Connect", just show that it's installed */ if (isGlobal) { return (

{t("default")}

); } return ( ( )} onChanged={handleOpenChange} /> ); } interface IntegrationsContainerProps { variant?: typeof InstalledAppVariants[number]; exclude?: typeof InstalledAppVariants[number][]; } interface IntegrationsListProps { variant?: IntegrationsContainerProps["variant"]; data: RouterOutputs["viewer"]["integrations"]; } const IntegrationsList = ({ data }: IntegrationsListProps) => { return ( {data.items .filter((item) => item.invalidCredentialIds) .map((item) => ( 0} actions={
}>
))}
); }; const IntegrationsContainer = ({ variant, exclude }: IntegrationsContainerProps): JSX.Element => { const { t } = useLocale(); const query = trpc.viewer.integrations.useQuery({ variant, exclude, onlyInstalled: true }); const emptyIcon = { calendar: FiCalendar, conferencing: FiVideo, automation: FiShare2, analytics: FiBarChart, payment: FiCreditCard, web3: FiBarChart, other: FiGrid, }; return ( } success={({ data }) => { return ( <> {data.items.length > 0 ? (
{t("add")} } />
) : ( {t(`connect_${variant || "other"}_apps`)} } /> )} ); }} /> ); }; const querySchema = z.object({ category: z.enum(InstalledAppVariants), }); type querySchemaType = z.infer; export default function InstalledApps() { const { t } = useLocale(); const router = useRouter(); const category = router.query.category as querySchemaType["category"]; const categoryList: querySchemaType["category"][] = [ "payment", "conferencing", "automation", "analytics", "web3", ]; return ( {categoryList.includes(category) && } {category === "calendar" && } {category === "other" && ( )} ); } // Server side rendering export async function getServerSideProps(ctx: AppGetServerSidePropsContext) { // get return-to cookie and redirect if needed const { cookies } = ctx.req; if (cookies && cookies["return-to"]) { const returnTo = cookies["return-to"]; if (returnTo) { ctx.res.setHeader("Set-Cookie", "return-to=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT"); return { redirect: { destination: `${returnTo}`, permanent: false, }, }; } } const params = querySchema.safeParse(ctx.params); if (!params.success) return { notFound: true }; return { props: { category: params.data.category, }, }; }